package handlers

import (
	"blog/configs"
	"blog/models"
	"blog/utils"
	"crypto/md5"
	"encoding/hex"
	"github.com/dgrijalva/jwt-go"
	"github.com/gofiber/fiber/v2"
	"github.com/mojocn/base64Captcha"
	"log"
	"math/rand"
	"strconv"
	"strings"
	"time"
)

// @Summary 获取名人名言
// @Tags 公共API
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Success 200 {object} Reply
// @Router /api/tip [get]
func GetTip(ctx *fiber.Ctx) error {
	var tip string
	rand.Seed(time.Now().Unix())
	if rand.Intn(2) != 0 {
		var err error
		tip, err = utils.GetRandTipFromWeb()
		if err != nil {
			log.Println(err)
			tip = utils.GetRandTipFromLocal()
		}
	} else {
		tip = utils.GetRandTipFromLocal()
	}
	return returnOk(ctx, tip)
}

// @Summary 获取管理员信息
// @Tags 公共API
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Success 200 {object} Reply
// @Router /api/admin [get]
func GetAdminInfo(ctx *fiber.Ctx) error {
	admin, err := models.GetAdmin()
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, admin)
}

// @Summary 更新管理员信息
// @Tags 管理员操作
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Param Authorization header string true "令牌"
// @param id formData integer true "id"
// @param name formData string true "名称"
// @param email formData string true "email"
// @param image formData string true "头像"
// @Success 200 {object} Reply
// @Router /api/admin/info [post]
func UpdateAdminInfo(ctx *fiber.Ctx) error {
	idStr := ctx.FormValue("id")
	id, err := strconv.ParseUint(idStr, 10, 32)
	if err != nil {
		return returnErrStr(ctx, "参数错误")
	}
	email := ctx.FormValue("email")
	name := ctx.FormValue("name")
	image := ctx.FormValue("image")

	admin, err := models.SaveAdmin(models.Admin{
		Id:    uint(id),
		Name:  name,
		Email: email,
		Image: image,
	})
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, admin)
}

// @Summary 获取验证码
// @Tags 登录
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Success 200 {object} Reply
// @Router /api/captcha [get]
func GetCaptcha(ctx *fiber.Ctx) error {
	bgColor := base64Captcha.RandLightColor()
	driver := base64Captcha.NewDriverString(70, 130, 2, 2, 4, base64Captcha.TxtAlphabet, &bgColor, nil, nil)
	c := base64Captcha.NewCaptcha(driver, configs.CaptchaStore)
	id, content, err := c.Generate()
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, map[string]interface{}{
		"id":  id,
		"img": content,
	})
}

// @Summary 管理员登录
// @Tags 登录
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Param pwd query string true "密码"
// @Param id query string true "验证码id"
// @Param code query string true "验证码"
// @Success 200 {object} Reply
// @Router /api/login [get]
func Login(ctx *fiber.Ctx) error {
	pwdMd5 := ctx.Query("pwd")
	id := ctx.Query("id")
	code := ctx.Query("code")
	// 验证验证码
	if configs.CaptchaStore.Verify(id, code, true) {
		return returnErrStr(ctx, "验证码错误")
	}
	// 对比密码
	crypto := md5.New()
	crypto.Write([]byte(configs.AdminPassword))
	pwdMd5Sure := hex.EncodeToString(crypto.Sum(nil))
	if pwdMd5 != pwdMd5Sure {
		return returnErrStr(ctx, "密码错误")
	}
	// 生成token
	expireTime := time.Now().Add(12 * time.Hour)
	token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
		ExpiresAt: expireTime.Unix(),
		IssuedAt:  time.Now().Unix(),
		Issuer:    "kkkunny",
	}).SignedString([]byte(configs.JWTSecret))
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, token)
}

// @Summary 分页获取简略文章
// @Tags 公共API
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @param page query integer true "页数"
// @param nums query integer true "数量"
// @param text query string false "搜索文本"
// @param column query integer false "栏目id"
// @param tags query string false "标签id列表"
// @Success 200 {object} Reply
// @router /api/small_articles [get]
func GetSmallArticlesByPage(ctx *fiber.Ctx) error {
	// 页数
	pageStr := ctx.Query("page")
	page, err := strconv.ParseUint(pageStr, 10, 32)
	if err != nil {
		return returnErrStr(ctx, "参数错误")
	}
	// 每页数量
	numsStr := ctx.Query("nums")
	nums, err := strconv.ParseUint(numsStr, 10, 32)
	if err != nil {
		return returnErrStr(ctx, "参数错误")
	}
	// 搜索文本
	text := ctx.Query("text")
	// 栏目
	column := -1
	columnStr := ctx.Query("column")
	if columnStr != "" {
		column, err = strconv.Atoi(columnStr)
		if err != nil {
			return returnErrStr(ctx, "参数错误")
		}
	}
	// 标签
	tagsStr := ctx.FormValue("tags")
	var tags []uint
	if tagsStr != "" {
		tagStrs := strings.Split(tagsStr, ",")
		for _, tagStr := range tagStrs {
			id, err := strconv.ParseUint(strings.TrimSpace(tagStr), 10, 32)
			if err != nil {
				return returnErrStr(ctx, "参数错误")
			}
			tags = append(tags, uint(id))
		}
	}
	// 获取简略文章
	as, err := models.GetSmallArticlesByPage(uint(page), uint(nums), text, column, tags)
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, as)
}

// @Summary 获取文章
// @Tags 公共API
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @param id query integer true "文章id"
// @Success 200 {object} Reply
// @router /api/article [get]
func GetArticle(ctx *fiber.Ctx) error {
	idStr := ctx.Query("id")
	id, err := strconv.ParseUint(idStr, 10, 32)
	if err != nil {
		return returnErrStr(ctx, "参数错误")
	}

	article, err := models.GetArticle(models.Article{Id: uint(id)})
	if err != nil {
		return returnErr(ctx, err)
	}
	article.View++
	if err = models.UpdateArticle(article.Id, article.View); err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, article)
}

// 校验管理员权限
func AdminTokenCheck(ctx *fiber.Ctx) error {
	// 获取token
	token := string(ctx.Request().Header.Peek("Authorization"))
	// 校验token
	tok, err := jwt.ParseWithClaims(token, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(configs.JWTSecret), nil
	})
	if err != nil || tok == nil || !tok.Valid {
		return returnErrStr(ctx, "无权限")
	}
	return ctx.Next()
}

// @Summary 获取专栏
// @Tags 公共API
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Success 200 {object} Reply
// @router /api/column [get]
func GetColumns(ctx *fiber.Ctx) error {
	columns, err := models.GetAllColumns()
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, columns)
}

// @Summary 测试登录
// @Tags 管理员操作
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Param Authorization header string true "令牌"
// @Success 200 {object} Reply
// @router /api/admin/test [get]
func AdminTest(ctx *fiber.Ctx) error {
	return returnOk(ctx, nil)
}

// @Summary 上传图片
// @Tags 管理员操作
// @Accept multipart/form-data
// @Produce application/json
// @Param Authorization header string true "令牌"
// @param file formData file true "图片"
// @Success 200 {object} Reply
// @router /api/admin/image [post]
func UploadImage(ctx *fiber.Ctx) error {
	fileHeader, err := ctx.FormFile("file")
	if err != nil {
		return returnErr(ctx, err)
	}
	file, err := fileHeader.Open()
	if err != nil {
		return returnErr(ctx, err)
	}
	defer file.Close()
	url, err := utils.UploadImageToSMMS(fileHeader.Filename, file)
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, url)
}

// @Summary 更新专栏
// @Tags 管理员操作
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Param Authorization header string true "令牌"
// @param id formData integer false "专栏id"
// @param name formData string true "专栏名"
// @Success 200 {object} Reply
// @router /api/admin/column [post]
func UpdateColumn(ctx *fiber.Ctx) error {
	idStr := ctx.FormValue("id")
	name := ctx.FormValue("name")
	var id uint
	if idStr != "" {
		idUint64, err := strconv.ParseUint(idStr, 10, 32)
		if err != nil {
			return returnErrStr(ctx, "参数错误")
		}
		id = uint(idUint64)
	}
	// 更新
	column, err := models.SaveColumn(models.Column{Id: id, Name: name})
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, column)
}

// @Summary 删除专栏
// @Tags 管理员操作
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Param Authorization header string true "令牌"
// @param id formData integer true "专栏id"
// @Success 200 {object} Reply
// @router /api/admin/column [delete]
func DeleteColumn(ctx *fiber.Ctx) error {
	idStr := ctx.FormValue("id")
	id, err := strconv.ParseUint(idStr, 10, 32)
	if err != nil {
		return returnErrStr(ctx, "参数错误")
	}
	// 删除
	column, err := models.DeleteColumn(models.Column{Id: uint(id)})
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, column)
}

// @Summary 删除多个专栏
// @Tags 管理员操作
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Param Authorization header string true "令牌"
// @param ids formData string true "专栏id列表"
// @Success 200 {object} Reply
// @router /api/admin/columns [delete]
func DeleteColumns(ctx *fiber.Ctx) error {
	idsStr := ctx.FormValue("ids")
	idStrs := strings.Split(idsStr, ",")
	var columns []models.Column
	for _, idStr := range idStrs {
		id, err := strconv.ParseUint(strings.TrimSpace(idStr), 10, 32)
		if err != nil {
			return returnErrStr(ctx, "参数错误")
		}
		columns = append(columns, models.Column{Id: uint(id)})
	}
	// 删除
	columns, err := models.DeleteColumns(columns)
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, columns)
}

// @Summary 获取标签
// @Tags 公共API
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Success 200 {object} Reply
// @router /api/tag [get]
func GetTags(ctx *fiber.Ctx) error {
	tags, err := models.GetAllTags()
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, tags)
}

// @Summary 更新标签
// @Tags 管理员操作
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Param Authorization header string true "令牌"
// @param id formData integer false "标签id"
// @param name formData string true "标签名"
// @Success 200 {object} Reply
// @router /api/admin/tag [post]
func UpdateTag(ctx *fiber.Ctx) error {
	idStr := ctx.FormValue("id")
	name := ctx.FormValue("name")
	var id uint
	if idStr != "" {
		idUint64, err := strconv.ParseUint(idStr, 10, 32)
		if err != nil {
			return returnErrStr(ctx, "参数错误")
		}
		id = uint(idUint64)
	}
	// 创建
	tag, err := models.SaveTag(models.Tag{Id: id, Name: name})
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, tag)
}

// @Summary 删除标签
// @Tags 管理员操作
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Param Authorization header string true "令牌"
// @param id formData integer true "标签id"
// @Success 200 {object} Reply
// @router /api/admin/tag [delete]
func DeleteTag(ctx *fiber.Ctx) error {
	idStr := ctx.FormValue("id")
	id, err := strconv.ParseUint(idStr, 10, 32)
	if err != nil {
		return returnErrStr(ctx, "参数错误")
	}
	// 创建
	tag, err := models.DeleteTag(models.Tag{Id: uint(id)})
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, tag)
}

// @Summary 删除多个标签
// @Tags 管理员操作
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Param Authorization header string true "令牌"
// @param ids formData string true "标签id列表"
// @Success 200 {object} Reply
// @router /api/admin/tags [delete]
func DeleteTags(ctx *fiber.Ctx) error {
	idsStr := ctx.FormValue("ids")
	idStrs := strings.Split(idsStr, ",")
	var tags []models.Tag
	for _, idStr := range idStrs {
		id, err := strconv.ParseUint(strings.TrimSpace(idStr), 10, 32)
		if err != nil {
			return returnErrStr(ctx, "参数错误")
		}
		tags = append(tags, models.Tag{Id: uint(id)})
	}
	// 删除
	tags, err := models.DeleteTags(tags)
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, tags)
}

// @Summary 更新文章
// @Tags 管理员操作
// @Accept multipart/form-data
// @Produce application/json
// @Param Authorization header string true "令牌"
// @param id formData integer false "文章id"
// @param title formData string true "标题"
// @param abstract formData string false "简介"
// @param column formData integer true "栏目id"
// @param tags formData string false "标签id列表"
// @param text formData string false "正文"
// @param create_time formData string false "创建时间"
// @param update_time formData string false "更新时间"
// @Success 200 {object} Reply
// @router /api/admin/article [post]
func UpdateArticle(ctx *fiber.Ctx) error {
	// id
	idStr := ctx.FormValue("id")
	var id uint
	if idStr != "" {
		idUint64, err := strconv.ParseUint(idStr, 10, 32)
		if err != nil {
			return returnErrStr(ctx, "参数错误")
		}
		id = uint(idUint64)
	}
	title := ctx.FormValue("title")       // 标题
	abstract := ctx.FormValue("abstract") // 简介
	// 专栏
	columnStr := ctx.FormValue("column")
	columnId, err := strconv.ParseUint(columnStr, 10, 32)
	if err != nil {
		return returnErrStr(ctx, "参数错误")
	}
	column, err := models.GetColumn(models.Column{Id: uint(columnId)})
	if err != nil {
		return returnErrStr(ctx, "参数错误")
	}
	// 标签
	tagsStr := ctx.FormValue("tags")
	var tags []models.Tag
	if tagsStr != "" {
		ss := strings.Split(tagsStr, ",")
		for _, s := range ss {
			tagId, err := strconv.ParseUint(strings.TrimSpace(s), 10, 32)
			if err != nil {
				return returnErrStr(ctx, "参数错误")
			}
			t, err := models.GetTag(models.Tag{Id: uint(tagId)})
			if err != nil {
				return returnErrStr(ctx, "参数错误")
			}
			tags = append(tags, t)
		}
	}

	text := ctx.FormValue("text")   // 正文
	cover := ctx.FormValue("cover") // 封面
	// 创建时间
	createTimeStr := ctx.FormValue("create_time")
	createTime := time.Now()
	if createTimeStr != "" {
		createTime, err = time.Parse("2006-1-2", createTimeStr)
		if err != nil {
			return returnErrStr(ctx, "参数错误")
		}
	}
	// 更新时间
	updateTimeStr := ctx.FormValue("update_time")
	updateTime := time.Now()
	if updateTimeStr != "" {
		updateTime, err = time.Parse("2006-1-2", updateTimeStr)
		if err != nil {
			return returnErrStr(ctx, "参数错误")
		}
	}
	// 保存
	view, _ := models.GetArticleView(id)
	article, err := models.SaveArticle(&models.Article{
		Id:         id,
		Title:      title,
		Abstract:   abstract,
		View:       view,
		Tags:       tags,
		Column:     column,
		Text:       text,
		Cover:      cover,
		CreateTime: createTime,
		UpdateTime: updateTime,
	})
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, article)
}

// @Summary 删除文章
// @Tags 管理员操作
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Param Authorization header string true "令牌"
// @param id formData integer true "文章id"
// @Success 200 {object} Reply
// @router /api/admin/article [delete]
func DeleteArticle(ctx *fiber.Ctx) error {
	idStr := ctx.FormValue("id")
	id, err := strconv.ParseUint(idStr, 10, 32)
	if err != nil {
		return returnErrStr(ctx, "参数错误")
	}

	article, err := models.DeleteArticle(models.Article{Id: uint(id)})
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, article)
}

// @Summary 删除多个文章
// @Tags 管理员操作
// @Accept application/x-www-form-urlencoded
// @Produce application/json
// @Param Authorization header string true "令牌"
// @param ids formData string true "文章id列表"
// @Success 200 {object} Reply
// @router /api/admin/articles [delete]
func DeleteArticles(ctx *fiber.Ctx) error {
	idsStr := ctx.FormValue("ids")
	idStrs := strings.Split(idsStr, ",")
	var as []models.Article
	for _, idStr := range idStrs {
		id, err := strconv.ParseUint(strings.TrimSpace(idStr), 10, 32)
		if err != nil {
			return returnErrStr(ctx, "参数错误")
		}
		as = append(as, models.Article{Id: uint(id)})
	}
	// 删除
	as, err := models.DeleteArticles(as)
	if err != nil {
		return returnErr(ctx, err)
	}
	return returnOk(ctx, as)
}
